package com.example.everying.service.user.impl;/*
 * 项目名称: everything
 * 文件名: UserServiceImpl
 * 作者: 张泽阳
 * 日期: 2025/5/14
 * 描述:
 */

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.everying.constant.CacheConstants;
import com.example.everying.context.UserContext;
import com.example.everying.mapper.user.UserMapper;
import com.example.everying.mapper.user.UserScoreMapper;
import com.example.everying.model.dto.admin.AdminLoginDto;
import com.example.everying.model.dto.user.*;
import com.example.everying.model.entity.invite.InviteCodeEntity;
import com.example.everying.model.entity.invite.InviteRecordsEntity;
import com.example.everying.model.entity.school.SchoolEntity;
import com.example.everying.model.entity.user.*;
import com.example.everying.model.vo.user.LoginUser;
import com.example.everying.model.vo.user.UserInfoVo;
import com.example.everying.model.vo.user.WxLoginVo;
import com.example.everying.service.school.SchoolService;
import com.example.everying.service.user.*;
import com.example.everying.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> implements UserService {
    @Value("${aliyun.oss.urlPrefix}")
    private String urlPrefix;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private InviteCodeService inviteCodeService;

    @Autowired
    private InviteRecordsService inviteRecordsService;

    @Autowired
    private UserLabelRelService userLabelRelService;

    @Autowired
    private LabelService labelService;

    @Autowired
    private UserBalanceService userBalanceService;

    @Autowired
    private PointsAccountService pointsAccountService;

    @Autowired
    private UserScoreMapper userScoreService;

    @Autowired
    private WxLoginServiceImpl wxLoginService;

    @Autowired
    private UserBindRelService userBindRelService;

    @Autowired
    private SchoolService schoolService;
    @Value("${aliyun.id-auth.api-url}")
    private String apiUrl;
    @Value("${aliyun.id-auth.app-code}")
    private String appCode;

    @Override
    public UserEntity getUserByOpenId(String openId) {
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("open_id", openId);
        queryWrapper.eq("is_delete", 0);
        queryWrapper.last("limit 1");

        return getOne(queryWrapper);
    }

    @Override
    public int insertUser(UserEntity user) {
        int insert = baseMapper.insert(user);
        return insert;
    }

    @Override
    public UserInfoVo getUserById(String id) {
        log.info("进入用户查询详情验证信息方法");

        //UserInfoVo userInfoVo = redisUtils.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + id);
        UserInfoVo userInfoVo = null;
        //UserInfoVo userInfoVo = null;
        if (userInfoVo == null) {
            UserEntity user = baseMapper.selectById(id);
            if (user == null) {
                return null;
            }
            userInfoVo = new UserInfoVo();

            //userInfoVo.setUserEntity(user);
            BeanUtil.copyProperties(user, userInfoVo);
            
            List<UserLabelRelEntity> labelByUserId = userLabelRelService.getLabelByUserId(id);
            if (labelByUserId == null || labelByUserId.size() == 0) {
                return userInfoVo;
            }
            List<String> labelIds = labelByUserId.stream().map(UserLabelRelEntity::getLabelId).collect(Collectors.toList());
            List<LabelEntity> labelPicUrls = labelService.getLabelPicUrls(labelIds);

            userInfoVo.setLabelPicUrls(labelPicUrls);

            InviteCodeEntity inviteCodeEntity = inviteCodeService.getInviteCodeByOwnerId(id);
            if (inviteCodeEntity == null) {
                throw new CampusException("用户未生成邀请码", 201);
            }
            userInfoVo.setInviteCode(inviteCodeEntity.getInviteCode());
/*            if (StringUtils.isEmpty(inviteCode)){
                throw new RuntimeException("用户未生成邀请码");
            }*/
            redisUtils.setCacheObject(id, userInfoVo);
            log.info("调用获取用户信息方法：" + userInfoVo);
            // log.info("最终返回是否认证："+userInfoVo.getisAuth());
            // log.info("最终返回是否认证："+user());
            return userInfoVo;

        }

        return userInfoVo;
    }


    @Override
    public UserInfoVo userEdit(UserEditDto userEditDto) {
        if (userEditDto.getIsDelete() == null) {
            userEditDto.setIsDelete(0);
        }
        //UserEntity userEntity = new UserEntity();
        // userEntity.setId(UserContext.getUser().getId());
        UserEntity userEntity = baseMapper.selectById(userEditDto.getId());
        BeanUtil.copyProperties(userEditDto, userEntity);
        if (StringUtils.isEmpty(userEntity.getBirthday())) {
            userEntity.setBirthday(null);
        }

        if (userEntity.getPassword() != null) {
            userEntity.setPassword(PaymentPasswordUtil.encrypt(userEntity.getPassword()));
        }

        List<String> labels = userEditDto.getLabels();

        userEntity.setUpdater(UserContext.getUser().getId());
        userEntity.setUpdateTime(LocalDateTime.now());

        // 添加关联标签
        // 删除用户所有标签
        if (UserContext.getUser().getIsAdministrator() != 1) {
            userLabelRelService.deleteLabelByUserId(userEntity.getId());
            if (labels != null && labels.size() > 0) {
                List<UserLabelRelEntity> userLabels = labels.stream().map(label -> new UserLabelRelEntity(RandomUtil.generateId(), userEntity.getId(), label)).collect(Collectors.toList());
                userLabelRelService.batchInsert(userLabels);
            }
        }

        boolean update = updateById(userEntity);
        LoginUser loginUser = redisUtils.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + userEntity.getId());
        UserInfoVo userInfoVo = getUserById(userEntity.getId());
        // 小程序用户修改
        if (loginUser != null) {

            BeanUtil.copyProperties(userInfoVo, loginUser);
            redisUtils.setCacheObject(CacheConstants.LOGIN_TOKEN_KEY + userEntity.getId(), loginUser);
            UserContext.clear();
            UserContext.setUser(userInfoVo);
            return userInfoVo;
        }
        // 管理员用户后台修改
/*        if (update == true){
            redisUtils.setCacheObject(userInfoVo.getId(),userInfoVo);
        }*/
        return userInfoVo;
    }

    @Override
    public Boolean deleteUser(DeleteUserDto ids) {


        List<UserEntity> userEntities = ids.getIds().stream().map(id ->
                new UserEntity().builder()
                        .id(id)
                        .isDelete(1)
                        .updateTime(LocalDateTime.now())
                        .build()
        ).collect(Collectors.toList());
        boolean flag = updateBatchById(userEntities);
        if (flag == true) {
            redisUtils.deleteObject(ids.getIds());
        }
        return flag;
    }

    @Override
    public Boolean uploadLocation(UploadLocationDto uploadLocation) {
        UserEntity userEntity = new UserEntity();
        userEntity.setId(UserContext.getUser().getId());
        userEntity.setLocation(uploadLocation.getLocation());
        boolean update = updateById(userEntity);
        if (update == true) {
            redisUtils.setCacheObject(userEntity.getId(), userEntity);
        }
        return update;
    }

    /**
     * 更新用户余额
     */
    @Override
    public void updateUserBalanceByOpenId(UserEntity user) {
        baseMapper.update(user, new LambdaUpdateWrapper<UserEntity>().eq(UserEntity::getOpenId, user.getOpenId()));
    }

    @Override
    public Result<?> updateInformation(UpdateInformationDto updateInformation) {

        UserEntity userEntity = new UserEntity();
        userEntity.setId(UserContext.getUser().getId());
        userEntity.setOpenId(UserContext.getUser().getOpenId());
        String code = userEntity.getInviteCode();
        BeanUtil.copyProperties(updateInformation, userEntity);
        userEntity.setInviteCode(code);
        userEntity.setUpdater(UserContext.getUser().getId());
        userEntity.setUpdateTime(LocalDateTime.now());
        SchoolEntity schoolByName = schoolService.getSchoolByName(updateInformation.getSchoolName());
        if (schoolByName == null || schoolByName.getSchoolName().isEmpty()) {
            return Result.fail("学校不存在");
        }
        userEntity.setSchoolId(schoolByName.getId());
        // 判断用户是否填写邀请码
        if (StringUtils.isEmpty(updateInformation.getInviteCode())) {
            // 更新用户学校认证信息
            updateById(userEntity);
            UserInfoVo user = getUserById(userEntity.getId());
            LoginUser loginUser = redisUtils.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + userEntity.getId());
            BeanUtil.copyProperties(user, loginUser);
            redisUtils.setCacheObject(CacheConstants.LOGIN_TOKEN_KEY + userEntity.getId(), loginUser);
            UserContext.clear();
            UserContext.setUser(user);
//            return Result.ok(getUserById(userEntity.getId()));
            return Result.ok(user);
        }
        // 用户填写了邀请码
        InviteCodeEntity inviteCodeInfo = inviteCodeService.getInviteCodeByCode(updateInformation.getInviteCode());
        //InviteRecordsEntity recordByInviteeId = inviteRecordsService.getRecordByInviteeId(userEntity.getId());
        InviteRecordsEntity recordByInviteeOpenId = inviteRecordsService.getRecordByInviteeOpenId(userEntity.getOpenId());
        if (recordByInviteeOpenId != null) {
            return Result.fail("您已经填写过邀请码了");
        }
        if (inviteCodeInfo == null) {
            return Result.fail("邀请码不存在");
        }
        // 邀请码不能是自己的
        if (inviteCodeInfo.getOwnerId().equals(userEntity.getId())) {
            return Result.fail("休想薅老板羊毛");
        }
        // 邀请码被使用次数+1
        inviteCodeInfo.setUseCount(inviteCodeInfo.getUseCount() + 1);
        inviteCodeService.updateById(inviteCodeInfo);

        InviteRecordsEntity inviteRecordsEntity = new InviteRecordsEntity();
        inviteRecordsEntity.setId(RandomUtil.generateId());
        inviteRecordsEntity.setOwnerId(inviteCodeInfo.getOwnerId());
        inviteRecordsEntity.setInviteCodeId(inviteCodeInfo.getId());
        inviteRecordsEntity.setInviteeId(userEntity.getId());
        inviteRecordsEntity.setInviteeOpenid(userEntity.getOpenId());
        inviteRecordsEntity.setUseTime(LocalDateTime.now());
        inviteRecordsService.save(inviteRecordsEntity);

        //todo 打钱


        // 更新用户学校认证信息
        userEntity.setInviterId(inviteCodeInfo.getOwnerId());
        updateById(userEntity);

        UserInfoVo user = getUserById(userEntity.getId());
        LoginUser loginUser = redisUtils.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + userEntity.getId());
        BeanUtil.copyProperties(user, loginUser);
        redisUtils.setCacheObject(CacheConstants.LOGIN_TOKEN_KEY + userEntity.getId(), loginUser);
        UserContext.clear();
        UserContext.setUser(user);
        return Result.ok(user);
    }

    /**
     * 认证并更新用户实名信息。
     * <p>
     * 该方法用于验证并更新用户的实名信息。首先检查提供的真实姓名是否为空，如果为空则返回错误结果。
     * 然后获取当前用户ID，并构建更新条件来更新用户的真实姓名。
     * 更新成功后，从数据库中重新获取更新后的用户信息，并从Redis缓存中获取登录用户对象。
     * 接着将新的用户信息复制到登录用户对象，并更新Redis中的缓存。
     * 最后清除当前线程的用户上下文，并设置更新后的用户信息。</p>
     *
     * @param updateInformation 包含新真实姓名的更新信息数据传输对象
     * @return Result<?> 操作结果，包含更新后的用户信息</p>
     */
    public Result<?> auth(AuthDto updateInformation) {
        if (StringUtils.isEmpty(updateInformation.getRealName())) {
            return Result.fail("请填写真实姓名");
        }
        String userId = UserContext.getUser().getId();
        boolean verified = verifyIdentity(updateInformation.getRealName(), updateInformation.getIdCard(), userId);
        if (!verified) {
            return Result.fail("验证失败,请填写正确的身份信息");
        }
//        UpdateWrapper<UserEntity> updateWrapper = new UpdateWrapper<>();
//        updateWrapper.set("real_name", updateInformation.getRealName());
//        updateWrapper.eq("id", userId);
//        update(updateWrapper);

        UserInfoVo user = getUserById(userId);
        // 更新Redis中的登录用户信息
        LoginUser loginUser = redisUtils.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + userId);
        BeanUtil.copyProperties(user, loginUser);
        redisUtils.setCacheObject(CacheConstants.LOGIN_TOKEN_KEY + userId, loginUser);
        // 清除并更新用户上下文
        UserContext.clear();
        UserContext.setUser(user);
        // UserEntity userEntity = baseMapper.selectById(updateInformation.getId());
        // userEntity.setUserAuth(false);
        // baseMapper.update(new QueryWrapper<>().eq(userId, userEntity));

        return Result.ok(user);
    }


    @Override
    public Result<?> list(UserPageDto userPageDto) {
        UserEntity userEntity = new UserEntity();
        BeanUtil.copyProperties(userPageDto, userEntity);
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(userEntity.getUserName() != null, UserEntity::getUserName, userEntity.getUserName());
        queryWrapper.like(userEntity.getRealName() != null, UserEntity::getRealName, userEntity.getRealName());
        queryWrapper.like(userEntity.getPhone() != null, UserEntity::getPhone, userEntity.getPhone());

//        if(userPageDto.getUserName() != null){
//            queryWrapper.like(UserEntity::getUserName,userEntity.getUserName());
//        }
//        if(userPageDto.getRealName() != null){
//            queryWrapper.like(UserEntity::getRealName,userEntity.getRealName());
//        }
//        if(userPageDto.getPhone() != null){
//            queryWrapper.like(UserEntity::getPhone,userEntity.getPhone());
//        }
        /*queryWrapper.eq(UserEntity::getIsDelete,0);*/
        Page<UserEntity> page = new Page<>(userPageDto.getPage(), userPageDto.getLimit());
        IPage<UserEntity> userEntityIPage = baseMapper.selectPage(page, queryWrapper);

        if (userEntityIPage != null) {
            return Result.ok(userEntityIPage);
        }
        return Result.fail("暂无数据");
    }

    @Override
    public Result<?> login(AdminLoginDto adminLoginDto) {
        UserEntity userEntity = new UserEntity();
        BeanUtil.copyProperties(adminLoginDto, userEntity);
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserEntity::getUserName, userEntity.getUserName());
        UserEntity user = baseMapper.selectOne(queryWrapper);
        if (user == null) {
            return Result.fail("用户不存在");
        }
        if (!(user.getPassword().equals(userEntity.getPassword()))) {
            return Result.fail("密码错误");
        }
        if (user.getIsAdministrator() != 1) {
            return Result.fail("权限不足");
        }
        String token = JwtUtils.sign(user.getId());

        saveTokenHash(user.getId(), token);
        return Result.ok(token);
    }

    @Override
    public Result<?> addUser(UserEntity user) {
        if (UserContext.getUser().getIsAdministrator() != 1) {
            return Result.fail("权限不足");
        }
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserEntity::getPhone, user.getPhone());
        UserEntity userEntity = baseMapper.selectOne(queryWrapper);
        if (userEntity != null) {
            return Result.fail("手机号已存在");
        }
        user.setId(RandomUtil.generateId());
        Random random = new Random();
        String imageName = String.valueOf((random.nextInt(5) + 1));
        String avatarUrl = urlPrefix + "/avatar/" + imageName + ".png";
        user.setAvatarUrl(avatarUrl);
        if (!(user.getPassword() == null)) {
            user.setPassword(PaymentPasswordUtil.encrypt(user.getPassword()));
        }
        if (user.getIsAdministrator() == null) {
            user.setIsAdministrator(2);
        }
        if (user.getUserName() == null || user.getUserName().equals("") || user.getUserName().isEmpty()) {
            user.setUserName("事包用户" + RandomUtil.generateName());
        }
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        user.setSignTime(LocalDateTime.now());
        user.setIsFirst(1); // 新用户注册
        // 生成邀请码
        InviteCodeEntity inviteCode = new InviteCodeEntity();
        inviteCode.setId(RandomUtil.generateId());
        inviteCode.setInviteCode(InviteCodeUtil.idToCode(Long.parseLong(user.getId())));
        inviteCode.setOwnerId(user.getId());
        inviteCode.setCreateTime(LocalDateTime.now());
        inviteCodeService.save(inviteCode);
        user.setInviteCode(inviteCode.getInviteCode());
        int insert = baseMapper.insert(user);
        if (insert > 0) {
            saveUserBalance(user);
            addUserScore(user.getId());
            addUserPoints(user.getId());
            return Result.ok("添加成功");
        }
        return Result.fail("新增失败");
    }

    @Override
    public List<UserEntity> getUserByPhone(String phone) {

        UserEntity userEntity = new UserEntity();
        userEntity.setPhone(phone);
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        if (phone != null) {
            queryWrapper.eq(UserEntity::getPhone, phone);
            queryWrapper.orderByDesc(UserEntity::getCreateTime);
            queryWrapper.eq(UserEntity::getIsDelete, 0);
        }
        List<UserEntity> userEntityList = baseMapper.selectList(queryWrapper);
        return userEntityList;
    }

/*    @Override
    public List<UserEntity> getUserByAdmin(String isAdministrator) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("is_administrator",isAdministrator);
        List<UserEntity> list = baseMapper.selectList(queryWrapper);

        return list;
    }*/

    public void saveTokenHash(String userId, String token) {
        String key = CacheConstants.LOGIN_TOKEN_KEY + userId;

        // 计算过期时间（当前时间+指定小时数）
        long expireTimestamp = System.currentTimeMillis() / 1000 + 7 * 24 * 3600;
        UserInfoVo userInfoVo = getUserById(userId);
        LoginUser loginUser = new LoginUser();
        loginUser.setToken(token);
        loginUser.setExpire(String.valueOf(expireTimestamp));
        BeanUtil.copyProperties(userInfoVo, loginUser);

        // 存储并设置TTL
        redisUtils.setCacheObject(key, loginUser);
        redisUtils.expire(key, CacheConstants.EXPIRE_DAYS, TimeUnit.DAYS);
    }

    @Override
    public Result<?> selectPageWithBalance(Page<UserInfoVo> pageParam, UserPageDto userPageDto) {
        return Result.ok(baseMapper.selectPageWithBalance(pageParam, userPageDto));
    }

    @Override
    public List<UserEntity> getUserByIds(Set<String> ids) {
        List<UserEntity> list = baseMapper.selectBatchIds(ids);
        return list;
    }

    /**
     * @param userId
     * @param password
     * @return
     */
    @Override
    public boolean verifyPassword(String userId, String password) {
        UserEntity userEntity = baseMapper.selectById(userId);
        if (userEntity.getPayPassword().isEmpty()) {
            throw new CampusException("请先设置支付密码", 201);
        }
        return PaymentPasswordUtil.verify(password, userEntity.getPayPassword());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean passwordUpdate(PasswordUpdateDto updateDto) {
        // 查询用户信息
        UserEntity userEntity = baseMapper.selectById(updateDto.getUserId());
        if (userEntity == null) {
            throw new CampusException("用户不存在", 201);
        }
        boolean verify = false;
        String type = updateDto.getType();

        // 校验是否已设置支付密码
        if (StringUtils.isEmpty(userEntity.getPayPassword()) && !"2".equals(type)) {
            throw new CampusException("请先设置支付密码", 201);
        }

        if ("0".equals(type)) {
            if (verifyPassword(userEntity.getId(), updateDto.getPayPassword())) {
                throw new CampusException("新密码不能与旧密码相同", 201);
            }
            // 使用旧密码验证
            verify = PaymentPasswordUtil.verify(updateDto.getOldPassword(), userEntity.getPayPassword());
        } else if ("1".equals(type)) {
            // 使用验证码验证
            String code = updateDto.getCode();
            if (StringUtils.isEmpty(code)) {
                throw new CampusException("验证码不能为空", 201);
            }

            String key = buildSmsCodeKey(updateDto.getUserId(), code);
            String cachedCode = redisUtils.getCacheObject(key);

            if (cachedCode == null || !cachedCode.equals(code)) {
                throw new CampusException("验证码错误或已过期", 201);
            }
            verify = true;
        } else if ("2".equals(type)) {
            verify = true;
        }

        if (!verify) {
            log.error("支付密码验证失败");
            return false;
        }

        // 加密并更新支付密码
        String encryptedPassword = PaymentPasswordUtil.encrypt(updateDto.getPayPassword());
        userEntity.setPayPassword(encryptedPassword);
        userEntity.setUpdateTime(LocalDateTime.now());
        int update = baseMapper.updateById(userEntity);

        if (update <= 0) {
            // 可选：记录日志或抛出异常
            throw new CampusException("支付密码更新失败", 201);
        }
        // 保存token
        saveTokenHash(userEntity.getId(), updateDto.getToken());
        return true;
    }

    @Override
    public void noticeUnreadCountPlus() {
        baseMapper.noticeUnreadCountPlus();
    }

    /**
     * 构建短信验证码缓存键
     */
    private String buildSmsCodeKey(String userId, String code) {
        return CacheConstants.SMS_CODE + userId + ":" + code;
    }

    // 获取用户名称
    @Override
    public String getUserNickname(String userId) {
        UserEntity user = baseMapper.selectById(userId);
        if (user.getUserName() == null) {
            return user.getRealName();
        }
        return user.getUserName();
    }

    // 获取用户头像
    @Override
    public String getUserAvatar(String userId) {
        UserEntity user = baseMapper.selectById(userId);
        return user.getAvatarUrl();
    }

    @Override
    public Integer getSignCount(LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.getSignCount(startTime, endTime);
    }

    /**
     * 获取指定日期的新增用户
     *
     * @param date
     * @return
     */
    @Override
    public List<String> getNewUserByDate(LocalDate date) {
        return baseMapper.getNewUserByDate(date);
    }


    @Override
    public boolean verifyIdentity(String realName, String idCard, String id) {
        UpdateWrapper<UserEntity> userEntity = new UpdateWrapper<>();
        userEntity.eq("id", id);
        // 创建验证器实例
        IdCardValidator validator = new IdCardValidator(apiUrl, appCode);

        try {
            // 示例验证
            String result = validator.validate(realName, idCard);
            if (StringUtils.isNotEmpty(result)) {
                JSONObject jsonResult = JSONObject.parseObject(result);
                String respCode = jsonResult.getString("respCode");
                if ("0000".equals(respCode)) {
                    userEntity.set("real_name", realName);
//                    userEntity.set("id_card", idCard);
                    userEntity.set("is_user_auth", true);
                    update(userEntity);
                    return true;
                }
            }
        } catch (Exception e) {
            System.err.println("未知错误: " + e.getMessage());
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 手机号绑定微信号
     * @param bindWxDto
     * @return
     */
    @Override
    public Result<?> bindWx(BindWxDto bindWxDto) {

        // 判断验证码
        String key = CacheConstants.SMS_CODE + bindWxDto.getPhone() + ":" + bindWxDto.getCode();
        String code = redisUtils.getCacheObject(key);
        if (code == null || !code.equals(bindWxDto.getCode())) {
            return Result.fail("验证码错误或已过期");
        }
        if (bindWxDto.getUnionId() == null){
            return Result.fail("网络故障");
        }
        if (bindWxDto.getOpenId() == null){
            return Result.fail("网络故障");
        }

        List<UserEntity> userEntityList = getUserByPhone(bindWxDto.getPhone());
        UserEntity userByPhone = userEntityList.size() > 0 ? userEntityList.get(0) : null;

        UserBindRel byUnionId = userBindRelService.getByUnionId(bindWxDto.getUnionId());
        if (byUnionId != null){
            return Result.fail("该微信已绑定手机号");
        }



        // 如果没有就注册
        if (userByPhone == null) {
            userByPhone = wxLoginService.register(bindWxDto.getPhone(), bindWxDto.getFirstPassword(), bindWxDto.getOpenId());
        }

        UserBindRel userBindRel = new UserBindRel();
        userBindRel.setUserId(userByPhone.getId());
        userBindRel.setPhone(bindWxDto.getPhone());
        userBindRel.setOpenId(bindWxDto.getOpenId());
        userBindRel.setUnionId(bindWxDto.getUnionId());
        userBindRel.setCreateTime(LocalDateTime.now());
        userBindRel.setUpdateTime(LocalDateTime.now());
        userBindRelService.save(userBindRel);

        WxLoginVo wxLoginVo = new WxLoginVo();
        wxLoginVo.setOpenId(userByPhone.getOpenId());
        String token = JwtUtils.sign(userByPhone.getId());
        saveTokenHash(userByPhone.getId(), token);
        wxLoginVo.setToken(token);
        wxLoginVo.setUsername(userByPhone.getUserName());
        wxLoginVo.setAvatarUrl(userByPhone.getAvatarUrl());
        wxLoginVo.setPhone(userByPhone.getPhone());
        wxLoginVo.setOpenId(userByPhone.getOpenId());

        return Result.ok(wxLoginVo);
    }

    @Override
    public boolean closePopup(String id) {
        log.info("关闭弹窗");
        UpdateWrapper<UserEntity> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", id);
        updateWrapper.set("popup_closed", true);
       return update(updateWrapper);
    }

    @Override
    public void saveTokenHash(UserInfoVo userInfoVo, String token) {
        saveTokenHash(userInfoVo.getId(), token);
    }

    @Override
    public Long getRegisterCount(String phone) {
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserEntity::getPhone, phone);
        return baseMapper.selectCount(queryWrapper);

    }

    @Async
    protected void saveUserBalance(UserEntity user) {
        // 初始化用户余额实体
        UserBalanceEntity userBalanceEntity = new UserBalanceEntity();
        userBalanceEntity.setUserId(user.getId());
        userBalanceEntity.setAvailableAmount(BigDecimal.ZERO);
        userBalanceEntity.setLastAmount(BigDecimal.ZERO);
        userBalanceEntity.setVersion(0);
        userBalanceEntity.setCreateTime(LocalDateTime.now());
        userBalanceEntity.setUpdateTime(LocalDateTime.now());
        // 保存用户余额实体到数据库
        userBalanceService.save(userBalanceEntity);
    }

    // 初始化有用户积分
    @Async
    public void addUserPoints(String id) {
        PointsAccount pointsAccount = new PointsAccount();
        pointsAccount.setUserId(id);
        pointsAccount.setTotalPoints(0);
        pointsAccount.setAvailablePoints(0);
        pointsAccount.setFrozenPoints(0);
        pointsAccount.setCreateTime(LocalDateTime.now());
        pointsAccount.setUpdateTime(LocalDateTime.now());
        pointsAccount.setVersion(0);
        pointsAccountService.save(pointsAccount);
    }

    @Async
    public void addUserScore(String id) {
        LambdaQueryWrapper<UserScore> scoreQueryWrapper = new LambdaQueryWrapper<>();
        scoreQueryWrapper.eq(UserScore::getUserId, id);
        if (userScoreService.selectCount(scoreQueryWrapper) == 0) {
            UserScore userScore = new UserScore();
            userScore.setUserId(id);
            userScore.setCreditWeight(0.0);
            userScore.setLastCreditUpdateMonth(LocalDateTime.now().getMonth().getValue());
            userScore.setCreateTime(LocalDateTime.now());
            userScore.setUpdateTime(LocalDateTime.now());
            userScoreService.insert(userScore);
        }
    }

    /**
     * 校验手机号是否合法
     * @param phoneNumber 待校验的手机号
     * @return true-合法 false-不合法
     */
    public static boolean isValidChinesePhoneNumber(String phoneNumber) {
        if (phoneNumber == null || phoneNumber.trim().isEmpty())  {
            return false;
        }

        // 正则表达式匹配中国大陆手机号
        // 1. 以1开头
        // 2. 第二位是3-9的数字
        // 3. 总共11位数字
        String regex = "^1[3-9]\\d{9}$";
        return Pattern.matches(regex,  phoneNumber);
    }

    /**
     * 校验密码长度是否为6-16位
     * @param password 待校验的密码
     * @return true-合法 false-不合法
     */
    public static boolean isValidPassword(String password) {
        if (password == null) {
            return false;
        }
        // 正则匹配：6-16位任意字符（包括特殊字符）
        String regex = "^.{6,16}$";
        return Pattern.matches(regex,  password);
    }

    /**
     * 检查用户余额是否充足
     *
     * @param userId 用户ID
     * @param amount 需要检查的金额
     * @param points 需要使用的积分
     * @return 如果用户余额充足返回true，否则返回false
     * @throws CampusException 当余额不足或积分不足时抛出异常
     */
    @Override
    public boolean checkUserBalance(String userId, BigDecimal amount, Integer points) {
        // 1. 获取用户余额信息
        if (points == null) {
            points = 0;
        }
        BigDecimal cashAmount = amount;
        UserBalanceEntity userBalanceEntity = userBalanceService.getBalanceByUserId(userId);
        if (userBalanceEntity == null) {
            return false;
        }
        BigDecimal availableAmount = userBalanceEntity.getAvailableAmount();
        // 2. 计算金额
        BigDecimal pointsAmount; // 积分金额
        if (points > 0) {
            pointsAmount = BigDecimal.valueOf(points).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
            cashAmount = cashAmount.subtract(pointsAmount);

            // 4. 检查用户积分账户
            PointsAccount userPoints = pointsAccountService.getByUid(userId);
            if (userPoints == null) {
                log.info("用户积分账户不存在");
                pointsAccountService.createPointsAccount(userId, 0);
                throw new CampusException("用户积分不足", 201);
            }
            // 5. 扣积分
            if (userPoints.getAvailablePoints() < points) {
                log.info("用户积分账户余额不足");
                throw new CampusException("用户积分不足", 201);
            }
        }

        // 3. 判断余额是否充足  要加上积分
        if (userBalanceEntity.getAvailableAmount().compareTo(cashAmount) < 0) {
            log.info("用户余额不足");
            throw new CampusException("余额不足", 201);
        }

        return availableAmount.compareTo(cashAmount) >= 0;
    }
}
